/**
 * @file hscuda_rasterview.h
 * @author iam002
 * @brief cuda版本RasterView模板类
 * @version 1.0
 * @date 2024-10-15
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#ifndef __HSCUDA_RASTERVIEW_H__
#define __HSCUDA_RASTERVIEW_H__

#include <limits>
#include <cmath>

namespace hscuda
{

namespace raster
{


/**
 * @brief CUDA版本RasterView类
 * @note 数据按照行优先存储, 无效数据默认为NaN
 * @tparam DataType 数据类型只支持float或double
 */
template<typename DataType>
class RasterView
{

public:

    /**
     * @brief 默认构造函数
     * 
     */
    RasterView()
        : m_pdata(nullptr), m_size_x(0), m_size_y(0)
    {
        setDefaultNodata();
    }


    /**
     * @brief 构造函数
     * 
     * @param size_x 图宽, x方向指水平方向
     * @param size_y 图高, y方向指竖直方向
     * @param pdata 数据指针
     */
    RasterView(int size_x, int size_y, DataType* pdata)
        : m_pdata(pdata), m_size_x(size_x), m_size_y(size_y)
    { 
        setDefaultNodata();
    }


    /**
     * @brief 初始化RasterView
     * 
     * @param size_x 图宽, x方向指水平方向
     * @param size_y 图高, y方向指竖直方向
     * @param pdata 数据指针
     */
    void init(int size_x, int size_y, DataType* pdata)
    {
        m_pdata = pdata;
        m_size_x = size_x;
        m_size_y = size_y;
        setDefaultNodata();
    }


    /**
     * @brief 设置为默认的无效数据
     * 
     */
    void setDefaultNodata()
    {
        m_nodata = std::numeric_limits<DataType>::quiet_NaN();
    }


    /**
     * @brief 设置无效数据
     * 
     * @param nodata 无效数据
     */
    void setNodata(DataType nodata)
    {
        m_nodata = nodata;
    }


    /**
     * @brief 是否存在无效值
     * 
     * @return true 存在无效值, nodata()返回值有效
     * @return false 不存在无效值, nodata()返回值无效
     */
    bool hasNodata() const
    {
        return !std::isnan(m_nodata);
    }


    /**
     * @brief 获取无效值
     * 
     * @return DataType 
     */
    DataType nodata() const
    {
        return m_nodata;
    }


    /**
     * @brief 清空RasterView
     * 
     */
    void clear()
    {
        m_size_x = 0;
        m_size_y = 0;
        m_pdata = nullptr;
    }


    /**
     * @brief 返回二维数据高(y方向, 竖直方向)
     * 
     * @return int 图高
     */
    int sizeY() const
    {
        return m_size_y;
    }


    /**
     * @brief 返回二维数据宽(x方向, 水平方向)
     * 
     * @return int 图宽
     */
    int sizeX() const
    {
        return m_size_x;
    }


    /**
     * @brief 返回数据总长度
     * 
     * @return int 数据总长度
     */
    int numel() const
    {
        return m_size_x * m_size_y;
    }


    /**
     * @brief 数据是否行优先存储
     * 
     * @return true 行优先存储
     * @return false 列优先存储
     */
    bool isRowMajor() const
    {
        return true;
    }


    /**
     * @brief 返回存放的数据指针
     * 
     * @return DataType* 数据指针
     */
    DataType* pData()
    {
        return m_pdata;
    }


    /**
     * @brief 返回存放的数据指针
     * 
     * @return DataType* 数据指针
     */
    const DataType* pData() const
    {
        return m_pdata;
    }


    /**
     * @brief 判断RasterView是否为空(即无数据指针)
     * 
     * @return true RasterView为空
     * @return false RasterView不为空
     */
    bool isEmpty() const
    {
        return m_pdata == nullptr;
    }
    

    /**
     * @brief 设置大小, 仅改变m_size_x与m_size_y
     * 
     * @param new_size_x 
     * @param new_size_y 
     */
    void _setSize(int new_size_x, int new_size_y)
    {
        m_size_x = new_size_x;
        m_size_y = new_size_y;
    }


protected:

    /// @brief 图宽
    int m_size_x;
    
    /// @brief 图高
    int m_size_y;

    /// @brief 数据指针
    DataType* m_pdata;

    /// @brief 无效数据
    DataType m_nodata;

private:
    /* 限定 DataType 必须为 float 或者 double */
    typename std::enable_if<std::is_same<DataType, double>::value || std::is_same<DataType, float>::value, void>::type _type_check() {}
};

} // end namespace raster

} // end namespace hscuda

#endif
